#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <iomanip>

using std::cout;
using std::endl;
using std::hex;


#pragma pack(1)
struct SEG_DESCRIPTOR 
{
	UINT16 limit_15_00; // max addressable unit
	UINT16 baseAddress_15_00;
	UINT16 baseAddress_23_16:8;
    UINT16 type:4; // expand if it works
	UINT16 sFlag:1; // 0 - system segment, 1 - code/data
    UINT16 pLvl:2; // 0 - kernel, 3 - user
    UINT16 presentFlag:1; // 1 - segment present in memory
    UINT16 limit_19_16:4;
    UINT16 AVL:1;
    UINT16 x86_64_LFlag:1;
    UINT16 defOpSize:1; // 0 - 16bit, 1 - 32bit
    UINT16 granularity:1; // 0 - 1B blocks, 1 - 4Kb blocks
	UINT16 baseAddress_31_24:8;
};
#pragma pack()

#pragma pack(1)
typedef struct _LDTR
{
	UINT16 rpl:2;
	UINT16 ti:1;
	UINT16 index:13;
} LDTR;
#pragma pack()

DWORD getBase(SEG_DESCRIPTOR desc) 
{
	DWORD baseAddress = 0;
	
	baseAddress = baseAddress + desc.baseAddress_31_24;
	baseAddress = baseAddress << 8;
	baseAddress = baseAddress + desc.baseAddress_23_16;
	baseAddress = baseAddress << 16;
	baseAddress = baseAddress + desc.baseAddress_15_00;

	return baseAddress;
}

DWORD getLimit(SEG_DESCRIPTOR desc)
{
	DWORD limit = 0;

	limit = limit + desc.limit_19_16;
	limit = limit << 16;
	limit = limit + desc.limit_15_00;

	return limit;
}

void printSD(SEG_DESCRIPTOR desc) 
{
	DWORD baseAddress = getBase(desc);
	DWORD limit = getLimit(desc);
	
	cout 
		<< "base: " << (void*) baseAddress << endl
		<< "limit: " << limit << endl
	    << "segment type: " << (char*) (desc.sFlag ? "code/data " : "system ") << endl
		<< "privilege level: " << desc.pLvl << endl
		<< "present in memory: " << desc.presentFlag << endl
		<< "default op size: " << (char*) (desc.defOpSize ? "32bit " : "16bit ") << desc.defOpSize <<endl
		<< "granularity: " << (char*) (desc.granularity ? "4Kb" : "1B") << endl
		<< endl;
}


int main()
{
	
	HANDLE hFile;
    DWORD dwReturn;
	unsigned char szTemp[2048] = {0};

	
    hFile = CreateFile(TEXT("\\\\.\\TestDriver"), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL);
    if (hFile)
    {
        std::cout << "file created" << std::endl;
		
		ReadFile(hFile, &szTemp, 2048, &dwReturn, NULL);
        CloseHandle(hFile);
    
		cout << "SEG_DESCRIPTOR size: " << sizeof(SEG_DESCRIPTOR) << endl;
		cout << "Read bytes from kernel: " << dwReturn << std::endl;
		
		int recs = dwReturn / sizeof(SEG_DESCRIPTOR);
		cout << "Total records: " << recs << endl;

		SEG_DESCRIPTOR* descriptors = (SEG_DESCRIPTOR*) szTemp;
		
		for (int i = 0; i < recs; ++i)
			printSD(descriptors[i]);
	
		cout << endl;
	
		LDTR ldtr;
		__asm {
			SLDT ldtr;
		}

	
		if (ldtr.index < recs) {
			SEG_DESCRIPTOR ltd_desc = descriptors[ldtr.index];
			SEG_DESCRIPTOR* ldt_entities = (SEG_DESCRIPTOR*) getBase(ltd_desc);

			DWORD gran = ltd_desc.granularity*4095 + 1;
			DWORD limit = getLimit(ltd_desc)*gran;

			cout << "Total records in LDT: " << (limit / 8) << endl;
			
			for (DWORD i = 0; i < (limit / 8); ++i) 
				printSD(ldt_entities[i]);
		}
	
	}
	

	std::cout << "end." << std::endl;
    return 0;
}